package com.huawei.java.main.deployentity;


import com.huawei.java.main.inputentity.ServerType;

import java.util.ArrayList;
import java.util.List;

/**
 * 已购买的服务器：服务器编号，剩余空间
 * 该类的id参数是必须的
 */
public class Server extends ServerType {

    private long id;
    //初始化节点资源，每个节点的CPU和内存在两个节点上均匀分配
    //节点A
    private int nodeARestCPU;
    private int nodeARestMemory;
    //节点B
    private int nodeBRestCPU;
    private int nodeBRestMemory;

    //标记是否是已经购买的服务器，默认没有购买
    private boolean isPurchased=false;

    //这台购买的服务器所部署的虚拟机
    private List<Vm> deployedVmList = new ArrayList<>();

    /**
     * 服务器剩余资源指标，|restCpu+restMemory|+|restCpu-restMemory|，数值越大表示资源剩余越多
     * @return
     */
    public int getRestResource(){
        // TODO: 2021/3/16 剩余资源计算似乎需要好好思考一下，如果cpu或memory之一清零了算是剩余资源少还是多呢？这里就暂时累加
        //  是否可以两种资源相减。差值越小说明分配越优秀？|restCpu-restMem|
        //  然后再k考虑两个的总资源|restCpu+restMem|
        //  相加是不是就可以反映分配的是否合理？
        int restCpu=getNodeARestCPU()+getNodeBRestCPU();
        int restMem=getNodeARestMemory()+getNodeBRestMemory();
        return restCpu+restMem+Math.abs(restCpu-restMem);
    }

    /**
     * 剩余资源占比，剩余资源/总资源 越低越好
     * @return
     */
    public double getRestResourceRate(){
        int restCpu = nodeARestCPU+nodeBRestCPU;
        int restMemory = nodeARestMemory+nodeBRestMemory;
        int totalCpu=super.getCPU();
        int totalMemory=super.getMemory();
        return (double)((restCpu+restMemory)+Math.abs(restCpu-restMemory))/(totalCpu+totalMemory);
    }

    /**
     * 当前剩余资源核内比
     * @return
     */
    public double currentCpuAndMemoryRatio(){
        int cpu = nodeARestCPU+nodeBRestCPU;
        int memory = nodeARestMemory+nodeBRestMemory;
        return (double)cpu/memory;
    }


    /**
     * @param id 该服务器的编号，必要
     * @param serverType 当前购买的服务器所属类型
     */
    public Server(long id, ServerType serverType) {
        super(serverType.getServerType(), serverType.getCPU(),serverType.getMemory(),serverType.getHardWareCost(),serverType.getDailyCost());
        this.id = id;
        nodeARestCPU=super.getCPU()/2;
        nodeARestMemory=super.getMemory()/2;

        nodeBRestCPU=super.getCPU()/2;
        nodeBRestMemory=super.getMemory()/2;
    }

    /**
     * 部署在该服务器上虚拟机列表
     * @return
     */
    public List<Vm> getDeployedVMList() {
        return deployedVmList;
    }

    /**
     * 添加虚拟机
     * @param vm
     */
    public void addVM(Vm vm){
        deployedVmList.add(vm);//部署虚拟机
        String node = vm.getNode();
        int cpu = vm.getCPU();
        int memory = vm.getMemory();
        switch (node){
            case "A":
                nodeARestCPU-=cpu;
                nodeARestMemory-=memory;
                break;
            case "B":
                nodeBRestCPU-=cpu;
                nodeBRestMemory-=memory;
                break;
            case "AB":
                nodeARestCPU-=cpu/2;
                nodeARestMemory-=memory/2;
                nodeBRestCPU-=cpu/2;
                nodeBRestMemory-=memory/2;
                break;
        }
    }

    /**
     * 释放虚拟机占用的资源
     * @param vm
     */
    public void releaseVM(Vm vm){
        //移除虚拟机
        deployedVmList.remove(vm);
        //释放资源
        String node = vm.getNode();
        int cpu = vm.getCPU();
        int memory = vm.getMemory();
        switch (node){
            case "A":
                nodeARestCPU+=cpu;
                nodeARestMemory+=memory;
                break;
            case "B":
                nodeBRestCPU+=cpu;
                nodeBRestMemory+=memory;
                break;
            case "AB":
                nodeARestCPU+=cpu/2;
                nodeARestMemory+=memory/2;
                nodeBRestCPU+=cpu/2;
                nodeBRestMemory+=memory/2;
                break;
        }
    }

    public long getId() {
        return id;
    }

    public void setId(int i) {
        this.id=i;
    }

    public int getNodeARestCPU() {
        return nodeARestCPU;
    }


    public int getNodeARestMemory() {
        return nodeARestMemory;
    }


    public int getNodeBRestCPU() {
        return nodeBRestCPU;
    }


    public int getNodeBRestMemory() {
        return nodeBRestMemory;
    }

    public boolean isPurchased() {
        return isPurchased;
    }

    public void setPurchased(boolean purchased) {
        isPurchased = purchased;
    }

    @Override
    public String toString() {
        return "Server{" +
                "id=" + id +
                ", nodeARestCPU=" + nodeARestCPU +
                ", nodeARestMemory=" + nodeARestMemory +
                ", nodeBRestCPU=" + nodeBRestCPU +
                ", nodeBRestMemory=" + nodeBRestMemory +
                ", serverType=" + getServerType() +
                '}';
    }

}
